import { Callout, Sandpack } from '@/components'

# useSuspenseInfiniteQuery

<Callout type='warning'>

**Deprecated in @suspensive/react-query**

This hook is now officially supported in TanStack Query v4.40.0+. Since TanStack Query has backported this interface, we are deprecating the backported version from @suspensive/react-query. Please migrate to the official TanStack Query interface:

```diff
- import { useSuspenseInfiniteQuery } from '@suspensive/react-query'
+ import { useSuspenseInfiniteQuery } from '@tanstack/react-query'
```

For more details, see [TanStack Query PR #9334](https://github.com/TanStack/query/pull/9334).

</Callout>

Return type of this hook have no isLoading, isError property. because `<Suspense/>` and `<ErrorBoundary/>` will guarantee this hook's data. In addition, this hook's options have default suspense: true. and you can provide new options to this hook like [useInfiniteQuery](https://tanstack.com/query/v4/docs/react/reference/useInfiniteQuery) of @tanstack/react-query.

```tsx /useSuspenseInfiniteQuery/
import { useSuspenseInfiniteQuery } from '@suspensive/react-query'

const Example = () => {
  const query = useSuspenseInfiniteQuery({
    queryKey,
    queryFn,
  }) // suspense:true is default.

  // No need to do type narrowing by isSuccess.
  query.data // InfiniteData<TData>
}
```

<Sandpack>

```tsx PostList.tsx active
import { useSuspenseInfiniteQuery } from '@suspensive/react-query'
import { useEffect, Fragment } from 'react'
import { getPosts } from './api'

export const PostList = () => {
  const { data, isFetchingNextPage, isFetched, hasNextPage, fetchNextPage } =
    useSuspenseInfiniteQuery({
      queryKey: ['posts'],
      queryFn: ({ pageParam = 1 }) => getPosts(pageParam),
      getNextPageParam: (lastPage, allPages) =>
        lastPage.skip + lastPage.limit < lastPage.total
          ? allPages.length + 1
          : undefined,
    })

  useEffect(() => {
    if (!isFetchingNextPage && isFetched) {
      window.scrollTo({
        top: document.body.scrollHeight,
        behavior: 'smooth',
      })
    }
  }, [isFetchingNextPage, isFetched])

  return (
    <div
      style={{
        display: 'flex',
        flexDirection: 'column',
        marginBottom: '100px',
      }}
    >
      <ol>
        {data.pages.map((page, i) => (
          <Fragment key={i}>
            {page.data.map((post) => (
              <li key={post.id} style={{ marginBottom: '10px' }}>
                {post.title}
              </li>
            ))}
          </Fragment>
        ))}
      </ol>
      <button
        onClick={() => fetchNextPage()}
        disabled={!hasNextPage || isFetchingNextPage}
      >
        {isFetchingNextPage
          ? 'Loading more...'
          : hasNextPage
            ? 'Load More'
            : 'Nothing more to load'}
      </button>
    </div>
  )
}
```

```tsx Example.tsx
import { Suspense } from '@suspensive/react'
import { PostList } from './PostList'

export const Example = () => {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <PostList />
    </Suspense>
  )
}
```

```tsx api.ts
type Post = {
  userId: number
  id: number
  title: string
  body: string
}

export const getPosts = async (
  page: number
): Promise<{
  data: Post[]
  page: number
  total: number
  limit: number
  skip: number
}> => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=10`
  )

  if (!response.ok) {
    throw new Error('An error occurred')
  }

  const data = await response.json()

  return {
    data,
    page,
    total: 100,
    limit: 10,
    skip: (page - 1) * 10,
  }
}
```

</Sandpack>

### Motivation

If you turn suspense on in @tanstack/react-query, You can use [useInfiniteQuery](https://tanstack.com/query/v4/docs/react/reference/useInfiniteQuery) with `<Suspense/>` and `<ErrorBoundary/>`.

```tsx /useInfiniteQuery/
import { useInfiniteQuery } from '@tanstack/react-query'

const Example = () => {
  const query = useInfiniteQuery({
    queryKey,
    queryFn,
    suspense: true,
  })

  query.data // InfiniteData<TData> | undefined

  if (query.isSuccess) {
    query.data // InfiniteData<TData>
  }
}
```

but useInfiniteQuery's return type:query.data will be always fulfilled because of `<Suspense/>` as parent of this component.

This is why @suspensive/react-query provide **useSuspenseInfiniteQuery**.

<Callout>

Concentrate on only Success.

Now, we can concentrate component as any fetching will be always success.

</Callout>

### Version History

| Version  | Changes                                                                                                                                   |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `v3.0.0` | `networkMode` has been fixed to `'always'`. For more details, please refer to the [Migration to v3 guide](./migration/migrate-to-v3.mdx). |
